#!/bin/bash
# RedFire 蓝绿部署脚本
# ====================
# 
# 实现零停机的蓝绿部署
# 支持自动健康检查、流量切换和回滚机制
# 
# 使用方法:
# ./blue-green-deploy.sh deploy <service> <image-tag> [namespace]
# ./blue-green-deploy.sh rollback <service> [namespace]
# ./blue-green-deploy.sh status <service> [namespace]

set -euo pipefail

# 脚本配置
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
KUBE_CONFIG_PATH="${HOME}/.kube/config"
DEFAULT_NAMESPACE="redfire-prod"
HEALTH_CHECK_TIMEOUT=300  # 5分钟
HEALTH_CHECK_INTERVAL=10  # 10秒

# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 日志函数
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# 检查依赖
check_dependencies() {
    log_info "检查依赖工具..."
    
    local deps=("kubectl" "jq" "curl")
    for dep in "${deps[@]}"; do
        if ! command -v "$dep" &> /dev/null; then
            log_error "缺少依赖工具: $dep"
            exit 1
        fi
    done
    
    # 检查kubectl连接
    if ! kubectl cluster-info &> /dev/null; then
        log_error "无法连接到Kubernetes集群"
        exit 1
    fi
    
    log_success "依赖检查通过"
}

# 获取当前活跃环境
get_active_environment() {
    local service=$1
    local namespace=$2
    
    local selector=$(kubectl get service "${service}-service" -n "$namespace" -o jsonpath='{.spec.selector.version}' 2>/dev/null || echo "")
    
    if [[ -z "$selector" ]]; then
        echo "blue"  # 默认为蓝色环境
    else
        echo "$selector"
    fi
}

# 获取非活跃环境
get_inactive_environment() {
    local active_env=$1
    
    if [[ "$active_env" == "blue" ]]; then
        echo "green"
    else
        echo "blue"
    fi
}

# 健康检查
health_check() {
    local service=$1
    local environment=$2
    local namespace=$3
    local timeout=$4
    
    log_info "开始健康检查: ${service}-${environment}"
    
    local end_time=$((SECONDS + timeout))
    local service_name="${service}-${environment}-service"
    
    # 检查Pod是否就绪
    while [[ $SECONDS -lt $end_time ]]; do
        local ready_pods=$(kubectl get pods -n "$namespace" -l "app=${service},version=${environment}" --field-selector=status.phase=Running -o json | jq '.items | length')
        local desired_replicas=$(kubectl get deployment "${service}-${environment}" -n "$namespace" -o jsonpath='{.spec.replicas}')
        
        if [[ "$ready_pods" -eq "$desired_replicas" ]] && [[ "$ready_pods" -gt 0 ]]; then
            log_info "Pod就绪检查通过: ${ready_pods}/${desired_replicas}"
            
            # 如果是网关服务，进行HTTP健康检查
            if [[ "$service" == "gateway" ]]; then
                if perform_http_health_check "$service_name" "$namespace"; then
                    log_success "健康检查通过: ${service}-${environment}"
                    return 0
                fi
            else
                log_success "健康检查通过: ${service}-${environment}"
                return 0
            fi
        fi
        
        log_info "等待Pod就绪... (${ready_pods}/${desired_replicas})"
        sleep $HEALTH_CHECK_INTERVAL
    done
    
    log_error "健康检查超时: ${service}-${environment}"
    return 1
}

# HTTP健康检查
perform_http_health_check() {
    local service_name=$1
    local namespace=$2
    
    log_info "执行HTTP健康检查..."
    
    # 使用kubectl port-forward进行健康检查
    local port_forward_pid
    kubectl port-forward service/"$service_name" 8080:8000 -n "$namespace" &
    port_forward_pid=$!
    
    sleep 5  # 等待端口转发建立
    
    local health_check_passed=false
    for i in {1..10}; do
        if curl -f -s http://localhost:8080/health > /dev/null 2>&1; then
            health_check_passed=true
            break
        fi
        log_info "HTTP健康检查尝试 $i/10..."
        sleep 2
    done
    
    # 清理端口转发
    kill $port_forward_pid 2>/dev/null || true
    
    if [[ "$health_check_passed" == "true" ]]; then
        log_success "HTTP健康检查通过"
        return 0
    else
        log_error "HTTP健康检查失败"
        return 1
    fi
}

# 部署到非活跃环境
deploy_to_inactive_environment() {
    local service=$1
    local image_tag=$2
    local namespace=$3
    local active_env=$4
    local inactive_env=$5
    
    log_info "部署 ${service}:${image_tag} 到 ${inactive_env} 环境"
    
    # 更新镜像标签
    kubectl set image deployment/"${service}-${inactive_env}" \
        "${service}=redfire/${service}:${image_tag}" \
        -n "$namespace"
    
    # 扩展非活跃环境副本数
    local active_replicas=$(kubectl get deployment "${service}-${active_env}" -n "$namespace" -o jsonpath='{.spec.replicas}')
    kubectl scale deployment "${service}-${inactive_env}" --replicas="$active_replicas" -n "$namespace"
    
    log_info "等待部署完成..."
    kubectl rollout status deployment/"${service}-${inactive_env}" -n "$namespace" --timeout=600s
    
    log_success "部署到 ${inactive_env} 环境完成"
}

# 切换流量
switch_traffic() {
    local service=$1
    local namespace=$2
    local new_env=$3
    
    log_info "切换流量到 ${new_env} 环境"
    
    # 更新服务选择器
    kubectl patch service "${service}-service" -n "$namespace" \
        -p "{\"spec\":{\"selector\":{\"version\":\"${new_env}\"}}}"
    
    log_success "流量已切换到 ${new_env} 环境"
}

# 缩减旧环境
scale_down_old_environment() {
    local service=$1
    local namespace=$2
    local old_env=$3
    
    log_info "缩减 ${old_env} 环境副本数"
    
    # 等待一段时间确保流量切换完成
    log_info "等待30秒确保流量切换完成..."
    sleep 30
    
    # 缩减旧环境到0副本
    kubectl scale deployment "${service}-${old_env}" --replicas=0 -n "$namespace"
    
    log_success "${old_env} 环境已缩减"
}

# 蓝绿部署主函数
blue_green_deploy() {
    local service=$1
    local image_tag=$2
    local namespace=${3:-$DEFAULT_NAMESPACE}
    
    log_info "开始蓝绿部署: ${service}:${image_tag}"
    
    # 获取当前活跃环境
    local active_env=$(get_active_environment "$service" "$namespace")
    local inactive_env=$(get_inactive_environment "$active_env")
    
    log_info "当前活跃环境: $active_env"
    log_info "目标部署环境: $inactive_env"
    
    # 部署到非活跃环境
    deploy_to_inactive_environment "$service" "$image_tag" "$namespace" "$active_env" "$inactive_env"
    
    # 健康检查
    if ! health_check "$service" "$inactive_env" "$namespace" $HEALTH_CHECK_TIMEOUT; then
        log_error "健康检查失败，回滚部署"
        kubectl scale deployment "${service}-${inactive_env}" --replicas=0 -n "$namespace"
        exit 1
    fi
    
    # 切换流量
    switch_traffic "$service" "$namespace" "$inactive_env"
    
    # 验证流量切换
    log_info "验证流量切换..."
    sleep 10
    
    if [[ "$service" == "gateway" ]]; then
        if ! perform_http_health_check "${service}-service" "$namespace"; then
            log_error "流量切换验证失败，执行回滚"
            switch_traffic "$service" "$namespace" "$active_env"
            exit 1
        fi
    fi
    
    # 缩减旧环境
    scale_down_old_environment "$service" "$namespace" "$active_env"
    
    log_success "蓝绿部署完成: ${service}:${image_tag}"
    log_info "当前活跃环境: $inactive_env"
}

# 快速回滚
quick_rollback() {
    local service=$1
    local namespace=${2:-$DEFAULT_NAMESPACE}
    
    log_info "开始快速回滚: $service"
    
    # 获取当前活跃环境
    local active_env=$(get_active_environment "$service" "$namespace")
    local inactive_env=$(get_inactive_environment "$active_env")
    
    log_info "当前活跃环境: $active_env"
    log_info "回滚到环境: $inactive_env"
    
    # 检查非活跃环境是否有可用的部署
    local inactive_replicas=$(kubectl get deployment "${service}-${inactive_env}" -n "$namespace" -o jsonpath='{.spec.replicas}')
    
    if [[ "$inactive_replicas" -eq 0 ]]; then
        log_warning "非活跃环境副本数为0，扩展到与活跃环境相同的副本数"
        local active_replicas=$(kubectl get deployment "${service}-${active_env}" -n "$namespace" -o jsonpath='{.spec.replicas}')
        kubectl scale deployment "${service}-${inactive_env}" --replicas="$active_replicas" -n "$namespace"
        
        # 等待Pod就绪
        kubectl rollout status deployment/"${service}-${inactive_env}" -n "$namespace" --timeout=300s
    fi
    
    # 健康检查
    if ! health_check "$service" "$inactive_env" "$namespace" 60; then
        log_error "回滚环境健康检查失败"
        exit 1
    fi
    
    # 切换流量
    switch_traffic "$service" "$namespace" "$inactive_env"
    
    # 验证回滚
    sleep 10
    if [[ "$service" == "gateway" ]]; then
        if ! perform_http_health_check "${service}-service" "$namespace"; then
            log_error "回滚验证失败"
            exit 1
        fi
    fi
    
    # 缩减原活跃环境
    scale_down_old_environment "$service" "$namespace" "$active_env"
    
    log_success "快速回滚完成"
    log_info "当前活跃环境: $inactive_env"
}

# 显示部署状态
show_status() {
    local service=$1
    local namespace=${2:-$DEFAULT_NAMESPACE}
    
    log_info "部署状态: $service"
    
    local active_env=$(get_active_environment "$service" "$namespace")
    local inactive_env=$(get_inactive_environment "$active_env")
    
    echo "============================================"
    echo "服务: $service"
    echo "命名空间: $namespace"
    echo "当前活跃环境: $active_env"
    echo "============================================"
    
    # 显示蓝色环境状态
    echo "蓝色环境 (Blue):"
    kubectl get deployment "${service}-blue" -n "$namespace" -o wide 2>/dev/null || echo "  未找到蓝色部署"
    
    echo ""
    echo "绿色环境 (Green):"
    kubectl get deployment "${service}-green" -n "$namespace" -o wide 2>/dev/null || echo "  未找到绿色部署"
    
    echo ""
    echo "服务状态:"
    kubectl get service "${service}-service" -n "$namespace" -o wide 2>/dev/null || echo "  未找到服务"
    
    echo ""
    echo "Pod状态:"
    kubectl get pods -n "$namespace" -l "app=${service}" -o wide
}

# 显示帮助信息
show_help() {
    cat << EOF
RedFire 蓝绿部署脚本

使用方法:
  $0 deploy <service> <image-tag> [namespace]    # 执行蓝绿部署
  $0 rollback <service> [namespace]              # 快速回滚
  $0 status <service> [namespace]                # 显示部署状态
  $0 help                                        # 显示帮助信息

参数:
  service      服务名称 (gateway, alpha-engine, chart-engine, vnpy-engine)
  image-tag    镜像标签
  namespace    Kubernetes命名空间 (默认: redfire-prod)

示例:
  $0 deploy gateway v2.1.0
  $0 deploy alpha-engine v2.1.0 redfire-prod
  $0 rollback gateway
  $0 status gateway redfire-prod

支持的服务:
  - gateway        API网关服务
  - alpha-engine   Alpha交易引擎
  - chart-engine   图表分析引擎
  - vnpy-engine    VnPy交易引擎

环境变量:
  KUBE_CONFIG_PATH           Kubernetes配置文件路径 (默认: ~/.kube/config)
  HEALTH_CHECK_TIMEOUT       健康检查超时时间 (默认: 300秒)
  HEALTH_CHECK_INTERVAL      健康检查间隔 (默认: 10秒)

EOF
}

# 主函数
main() {
    if [[ $# -eq 0 ]]; then
        show_help
        exit 1
    fi
    
    local command=$1
    shift
    
    check_dependencies
    
    case $command in
        deploy)
            if [[ $# -lt 2 ]]; then
                log_error "部署命令需要服务名和镜像标签参数"
                show_help
                exit 1
            fi
            blue_green_deploy "$@"
            ;;
        rollback)
            if [[ $# -lt 1 ]]; then
                log_error "回滚命令需要服务名参数"
                show_help
                exit 1
            fi
            quick_rollback "$@"
            ;;
        status)
            if [[ $# -lt 1 ]]; then
                log_error "状态命令需要服务名参数"
                show_help
                exit 1
            fi
            show_status "$@"
            ;;
        help|--help|-h)
            show_help
            ;;
        *)
            log_error "未知命令: $command"
            show_help
            exit 1
            ;;
    esac
}

# 执行主函数
main "$@"
